`timescale 1ns / 1ps

module alu(
    input  [15:0] alu_control,  // ALU 控制信号
    input  [31:0] alu_src1,     // ALU 操作数1
    input  [31:0] alu_src2,     // ALU 操作数2
    output [31:0] alu_result    // ALU 结果
);

    // ALU 控制信号
    wire alu_add;   // 加法
    wire alu_sub;   // 减法
    wire alu_slt;   // 有符号比较，小于置位
    wire alu_sltu;  // 无符号比较，小于置位
    wire alu_and;   // 按位与
    wire alu_nor;   // 按位或非
    wire alu_or;    // 按位或
    wire alu_xor;   // 按位异或
    wire alu_sll;   // 逻辑左移
    wire alu_srl;   // 逻辑右移
    wire alu_sra;   // 算术右移
    wire alu_lui;   // 高位加载
    wire alu_rol;   // 旋转左移
    wire alu_ror;   // 旋转右移
    wire alu_div;   // 除法
    wire alu_mul;   // 乘法
    
    assign alu_mul  = alu_control[15];
    assign alu_div  = alu_control[14];
    assign alu_rol  = alu_control[13];
    assign alu_ror  = alu_control[12];
    assign alu_add  = alu_control[11];
    assign alu_sub  = alu_control[10];
    assign alu_slt  = alu_control[ 9];
    assign alu_sltu = alu_control[ 8];
    assign alu_and  = alu_control[ 7];
    assign alu_nor  = alu_control[ 6];
    assign alu_or   = alu_control[ 5];
    assign alu_xor  = alu_control[ 4];
    assign alu_sll  = alu_control[ 3];
    assign alu_srl  = alu_control[ 2];
    assign alu_sra  = alu_control[ 1];
    assign alu_lui  = alu_control[ 0]; 

    // 中间结果
    wire [31:0] add_sub_result;
    wire [31:0] slt_result;
    wire [31:0] sltu_result;
    wire [31:0] and_result;
    wire [31:0] nor_result;
    wire [31:0] or_result;
    wire [31:0] xor_result;
    wire [31:0] sll_result;
    wire [31:0] srl_result;
    wire [31:0] sra_result;
    wire [31:0] lui_result;

    //逻辑运算
    assign and_result = alu_src1 & alu_src2;      // 按位与
    assign or_result  = alu_src1 | alu_src2;      // 按位或
    assign nor_result = ~or_result;               // 按位或非
    assign xor_result = alu_src1 ^ alu_src2;      // 按位异或
    assign lui_result = {alu_src2[15:0], 16'd0};  // 高位加载

    //add,sub
    wire [31:0] adder_operand1;
    wire [31:0] adder_operand2;
    wire        adder_cin     ;
    wire [31:0] adder_result  ;
    wire        adder_cout    ;
    assign adder_operand1 = alu_src1; 
    assign adder_operand2 = alu_add ? alu_src2 : ~alu_src2; //add or sub
    assign adder_cin      = ~alu_add;  // A - B = A + (-B) = A + (~B + 1)
    adder adder_module(
    .operand1(adder_operand1),
    .operand2(adder_operand2),
    .cin     (adder_cin     ),
    .result  (adder_result  ),
    .cout    (adder_cout    )
    );

    assign add_sub_result = adder_result;



    //slt: set less than
    assign slt_result[31:1] = 31'd0;    //the result only need one single bit, so use slt_result[0] to store the result.

    assign slt_result[0] = (alu_src1[31] & ~alu_src2[31]) | (~(alu_src1[31]^alu_src2[31]) & adder_result[31]);
                            //  (src1 < 0 and src2 > 0)   or ( (the sign bits are the same) and (src1 - src2 < 0) )                   

    //sltu: set less than unsigned
    assign sltu_result = {31'd0, ~adder_cout}; //determine whether src1 - src2 < 0



    //sll and srl
    wire [4:0] shf;
    assign shf = alu_src1[4:0];
    wire [1:0] shf_1_0;
    wire [1:0] shf_3_2;
    assign shf_1_0 = shf[1:0];
    assign shf_3_2 = shf[3:2];
    
    //sll: shift left logical
    wire [31:0] sll_step1;  //the first sll
    wire [31:0] sll_step2;  //the second sll
    assign sll_step1 = {32{shf_1_0 == 2'b00}} & alu_src2                   
                     | {32{shf_1_0 == 2'b01}} & {alu_src2[30:0], 1'd0}     
                     | {32{shf_1_0 == 2'b10}} & {alu_src2[29:0], 2'd0}     
                     | {32{shf_1_0 == 2'b11}} & {alu_src2[28:0], 3'd0};    
    assign sll_step2 = {32{shf_3_2 == 2'b00}} & sll_step1                  
                     | {32{shf_3_2 == 2'b01}} & {sll_step1[27:0], 4'd0}    
                     | {32{shf_3_2 == 2'b10}} & {sll_step1[23:0], 8'd0}    
                     | {32{shf_3_2 == 2'b11}} & {sll_step1[19:0], 12'd0};  
    assign sll_result = shf[4] ? {sll_step2[15:0], 16'd0} : sll_step2;     //if shf[4] = 1, keep the lower 16 bits

    //srl: shift right logical
    wire [31:0] srl_step1;
    wire [31:0] srl_step2;
    assign srl_step1 = {32{shf_1_0 == 2'b00}} & alu_src2                   
                     | {32{shf_1_0 == 2'b01}} & {1'd0, alu_src2[31:1]}     
                     | {32{shf_1_0 == 2'b10}} & {2'd0, alu_src2[31:2]}     
                     | {32{shf_1_0 == 2'b11}} & {3'd0, alu_src2[31:3]};    
    assign srl_step2 = {32{shf_3_2 == 2'b00}} & srl_step1                  
                     | {32{shf_3_2 == 2'b01}} & {4'd0, srl_step1[31:4]}    
                     | {32{shf_3_2 == 2'b10}} & {8'd0, srl_step1[31:8]}    
                     | {32{shf_3_2 == 2'b11}} & {12'd0, srl_step1[31:12]}; 
    assign srl_result = shf[4] ? {16'd0, srl_step2[31:16]} : srl_step2;    
 
    //sra: shift right arithmetic
    wire [31:0] sra_step1;  //the first sra
    wire [31:0] sra_step2;  //the second sra
    assign sra_step1 = {32{shf_1_0 == 2'b00}} & alu_src2                                 
                     | {32{shf_1_0 == 2'b01}} & {alu_src2[31], alu_src2[31:1]}           
                     | {32{shf_1_0 == 2'b10}} & {{2{alu_src2[31]}}, alu_src2[31:2]}      
                     | {32{shf_1_0 == 2'b11}} & {{3{alu_src2[31]}}, alu_src2[31:3]};     
                     
    assign sra_step2 = {32{shf_3_2 == 2'b00}} & sra_step1                                
                     | {32{shf_3_2 == 2'b01}} & {{4{sra_step1[31]}}, sra_step1[31:4]}    
                     | {32{shf_3_2 == 2'b10}} & {{8{sra_step1[31]}}, sra_step1[31:8]}    
                     | {32{shf_3_2 == 2'b11}} & {{12{sra_step1[31]}}, sra_step1[31:12]}; 
    assign sra_result = shf[4] ? {{16{sra_step2[31]}}, sra_step2[31:16]} : sra_step2;    

    //rotate left
    // wire [31:0] rol_result;
    // Rotate_Left rol(
    //     .rol_src1(alu_src1),
    //     .rol_src2(alu_src2),
    //     .rol_result(rol_result)
    // );

    //rotate right
    wire [31:0] ror_result;
    Rotate_Right ror(
        .ror_src1(alu_src1),
        .ror_src2(alu_src2),
        .ror_result(ror_result)
    );

    //rotate left
    wire [31:0] rol_result;
    wire [4:0] rol_shift_amount;
    assign rol_shift_amount = 5'd32 - alu_src1[4:0];

    Rotate_Right rol(
        .ror_src1(rol_shift_amount),
        .ror_src2(alu_src2),
        .ror_result(rol_result)
    );

    wire alu_div;   //divide
    wire [31:0] div_quotient;
    wire [31:0] div_remainder;
    assign alu_div  = alu_control[14]; //除法器控制信号

    wire [31:0] div_result;
    divider div(
        .dividend(alu_src1),
        .divisor(alu_src2),
        .quotient(div_quotient),
        .remainder(div_remainder)
    );
    assign div_result = div_quotient;
    
    // Booth 乘法器
    wire [31:0] mul_result; // 64位乘法结果
    booth_multiplier booth_mul( 
        .mul_src1(alu_src1),
        .mul_src2(alu_src2),
        .mul_result(mul_result)
    );

    // 结果选择
    assign alu_result = (alu_add | alu_sub) ? add_sub_result :
                        alu_slt            ? slt_result :
                        alu_sltu           ? sltu_result :
                        alu_and            ? and_result :
                        alu_nor            ? nor_result :
                        alu_or             ? or_result :
                        alu_xor            ? xor_result :
                        alu_sll            ? sll_result :
                        alu_srl            ? srl_result :
                        alu_sra            ? sra_result :
                        alu_lui            ? lui_result :
                        alu_rol            ? rol_result :
                        alu_ror            ? ror_result :
                        alu_div            ? div_result :
                        alu_mul            ? mul_result : // 乘法结果截取低32位
                        32'd0;
endmodule
